using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;

namespace TMPAnimationLib
{
    /// <summary>
    /// 字符动画调度器
    /// </summary>
    public class AnimSchedule : IAnimSchedule
    {
        /// <summary>
        /// 单个字符动画的完成事件
        /// </summary>
        public event Action<CharObject> SingleCharAnimCompletedEvent;

        /// <summary>
        /// 所有字符动画完成后的事件
        /// </summary>
        public event Action TotalAnimCompletedEvent;

        /// <summary>
        /// 调度状态
        /// </summary>
        public StateType ScheduleState { get; private set; }


        AnimConfig mConfig;
        CharObject[] mCharArray;
        HashSet<int> mCompletedSet;


        public void Init(IAnimConfig config, CharObject[] charArray)
        {
            mConfig = (AnimConfig) config;
            mCharArray = charArray;
            mCompletedSet ??= new HashSet<int>();
            mCompletedSet.Clear();
            ScheduleState = StateType.Wait;
            SingleCharAnimCompletedEvent = null;
            TotalAnimCompletedEvent = null;
        }

        public void Dispose()
        {
            mConfig = null;
            mCharArray = null;
            mCompletedSet = null;
            ScheduleState = StateType.None;
        }

        public void OnUpdate()
        {
            if (ScheduleState != StateType.Running) return;

            float deltaTime = Time.deltaTime;
            bool isCompleted = true;
            for (int i = 0; i < mCharArray.Length; i++)
            {
                var charObj = mCharArray[i];
                var state = charObj.OnUpdate(deltaTime);
                if (state != StateType.Completed)
                    isCompleted = false;
                else
                {
                    if (!mCompletedSet.Contains(i))
                    {
                        mCompletedSet.Add(i);
                        OnSingleCharAnimCompleted(charObj);
                    }
                }
            }

            if (isCompleted)
                OnTotalAnimCompleted();
        }

        /// <summary>
        /// 开始调度
        /// </summary>
        public void Start()
        {
            Assert.IsTrue(ScheduleState != StateType.None);
            if (ScheduleState == StateType.Running) return;
            if (ScheduleState == StateType.Completed)
                Reset();
            //start
            ScheduleState = StateType.Running;
            foreach (var charObject in mCharArray)
                charObject.Start();
        }

        /// <summary>
        /// 停止调度
        /// </summary>
        public void Stop()
        {
            Assert.IsTrue(ScheduleState != StateType.None);
            if (ScheduleState == StateType.Wait ||
                ScheduleState == StateType.Completed) return;
            //stop
            ScheduleState = StateType.Completed;
            foreach (var charObject in mCharArray)
                charObject.Stop();
            SingleCharAnimCompletedEvent = null;
            TotalAnimCompletedEvent = null;
        }

        /// <summary>
        /// 重置调度
        /// </summary>
        public void Reset()
        {
            Assert.IsTrue(ScheduleState != StateType.None);
            if (ScheduleState == StateType.Wait) return;
            if (ScheduleState == StateType.Running)
                Stop();
            //reset
            ScheduleState = StateType.Wait;
            foreach (var charObject in mCharArray)
                charObject.Reset();
        }

        /// <summary>
        /// 单个字符动画完成时调用
        /// </summary>
        void OnSingleCharAnimCompleted(CharObject obj)
        {
            SingleCharAnimCompletedEvent?.Invoke(obj);
        }

        /// <summary>
        /// 所有字符动画完成时调用
        /// </summary>
        void OnTotalAnimCompleted()
        {
            if (mConfig.IsHideCharAfterAllAnimEnd)
            {
                foreach (var item in mCharArray)
                    item.Hide();
            }
            TotalAnimCompletedEvent?.Invoke();
            TotalAnimCompletedEvent = null;
        }
    }
}